//
//  IMEncryptUtils.m
//  DualMediationSDK
//
//  Created by YeJary on 2025/6/23.
//

#import "IMEncryptUtils.h"
#import <CommonCrypto/CommonCrypto.h>

@implementation IMEncryptUtils

#pragma mark - Hash Functions

+ (NSString *)md5:(NSString *)string {
    if (!string) return nil;
    
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), digest);
    
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02x", digest[i]];
    }
    
    return [result copy];
}

+ (NSString *)sha1:(NSString *)string {
    if (!string) return nil;
    
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(cStr, (CC_LONG)strlen(cStr), digest);
    
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02x", digest[i]];
    }
    
    return [result copy];
}

+ (NSString *)sha256:(NSString *)string {
    if (!string) return nil;
    
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(cStr, (CC_LONG)strlen(cStr), digest);
    
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02x", digest[i]];
    }
    
    return [result copy];
}

+ (NSString *)hmacSHA256:(NSString *)string withKey:(NSString *)key {
    if (!string || !key) return nil;
    
    const char *cKey = [key UTF8String];
    const char *cData = [string UTF8String];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02x", cHMAC[i]];
    }
    
    return [result copy];
}

#pragma mark - Base64 Encoding/Decoding

+ (NSString *)base64EncodeData:(NSData *)data {
    if (!data) return nil;
    return [data base64EncodedStringWithOptions:0];
}

+ (NSString *)base64EncodeString:(NSString *)string {
    if (!string) return nil;
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    return [self base64EncodeData:data];
}

+ (NSData *)base64DecodeString:(NSString *)string {
    if (!string) return nil;
    return [[NSData alloc] initWithBase64EncodedString:string options:0];
}

+ (NSString *)base64DecodeToString:(NSString *)string {
    NSData *data = [self base64DecodeString:string];
    if (!data) return nil;
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

#pragma mark - AES Encryption/Decryption

+ (NSData *)aesEncryptData:(NSData *)data withKey:(NSString *)key {
    return [self aesOperation:kCCEncrypt data:data key:key];
}

+ (NSData *)aesDecryptData:(NSData *)data withKey:(NSString *)key {
    return [self aesOperation:kCCDecrypt data:data key:key];
}

+ (NSString *)aesEncryptString:(NSString *)string withKey:(NSString *)key {
    if (!string || !key) return nil;
    
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSData *encryptedData = [self aesEncryptData:data withKey:key];
    return [self base64EncodeData:encryptedData];
}

+ (NSString *)aesDecryptString:(NSString *)string withKey:(NSString *)key {
    if (!string || !key) return nil;
    
    NSData *data = [self base64DecodeString:string];
    NSData *decryptedData = [self aesDecryptData:data withKey:key];
    return [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
}

+ (NSData *)aesOperation:(CCOperation)operation data:(NSData *)data key:(NSString *)key {
    if (!data || !key) return nil;
    
    // 确保key长度为32字节（AES-256）
    NSMutableData *keyData = [NSMutableData dataWithCapacity:kCCKeySizeAES256];
    NSData *sourceKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    
    if (sourceKey.length < kCCKeySizeAES256) {
        [keyData appendData:sourceKey];
        // 用0填充至32字节
        NSUInteger remaining = kCCKeySizeAES256 - sourceKey.length;
        [keyData increaseLengthBy:remaining];
    } else {
        [keyData appendBytes:sourceKey.bytes length:kCCKeySizeAES256];
    }
    
    // 初始化向量 (IV)
    char iv[kCCBlockSizeAES128];
    memset(iv, 0, sizeof(iv));
    
    size_t bufferSize = data.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesProcessed = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                        kCCAlgorithmAES128,
                                        kCCOptionPKCS7Padding,
                                        keyData.bytes,
                                        kCCKeySizeAES256,
                                        iv,
                                        data.bytes,
                                        data.length,
                                        buffer,
                                        bufferSize,
                                        &numBytesProcessed);
    
    if (cryptStatus == kCCSuccess) {
        NSData *result = [NSData dataWithBytes:buffer length:numBytesProcessed];
        free(buffer);
        return result;
    }
    
    free(buffer);
    return nil;
}

#pragma mark - URL Encoding/Decoding

+ (NSString *)urlEncode:(NSString *)string {
    if (!string) return nil;
    
    NSCharacterSet *allowedCharacters = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"];
    return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
}

+ (NSString *)urlDecode:(NSString *)string {
    if (!string) return nil;
    return [string stringByRemovingPercentEncoding];
}

#pragma mark - Random Generation

+ (NSString *)randomString:(NSUInteger)length {
    static NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
    
    for (NSUInteger i = 0; i < length; i++) {
        uint32_t randomIndex = arc4random_uniform((uint32_t)letters.length);
        [randomString appendFormat:@"%C", [letters characterAtIndex:randomIndex]];
    }
    
    return [randomString copy];
}

+ (NSData *)randomData:(NSUInteger)length {
    NSMutableData *data = [NSMutableData dataWithLength:length];
    int result = SecRandomCopyBytes(kSecRandomDefault, length, data.mutableBytes);
    if (result != errSecSuccess) {
        return nil;
    }
    return [data copy];
}

+ (NSString *)uuid {
    return [[NSUUID UUID] UUIDString];
}

#pragma mark - Key Derivation

+ (NSData *)pbkdf2WithPassword:(NSString *)password 
                          salt:(NSData *)salt 
                     keyLength:(NSUInteger)keyLength 
                        rounds:(NSUInteger)rounds {
    if (!password || !salt) return nil;
    
    NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *derivedKey = [NSMutableData dataWithLength:keyLength];
    
    int result = CCKeyDerivationPBKDF(kCCPBKDF2,
                                    passwordData.bytes,
                                    passwordData.length,
                                    salt.bytes,
                                    salt.length,
                                    kCCPRFHmacAlgSHA256,
                                    (uint)rounds,
                                    derivedKey.mutableBytes,
                                    derivedKey.length);
    
    return (result == kCCSuccess) ? [derivedKey copy] : nil;
}

#pragma mark - Digital Signature Verification

+ (BOOL)verifyData:(NSData *)data 
         signature:(NSData *)signature 
         publicKey:(SecKeyRef)publicKey {
    if (!data || !signature || !publicKey) return NO;
    
    // 这里应该实现具体的签名验证逻辑
    // 根据实际使用的签名算法进行实现
    return NO;
}

#pragma mark - Utility Methods

+ (NSString *)hexStringFromData:(NSData *)data {
    if (!data) return nil;
    
    NSMutableString *hex = [NSMutableString stringWithCapacity:data.length * 2];
    const unsigned char *bytes = data.bytes;
    for (NSUInteger i = 0; i < data.length; i++) {
        [hex appendFormat:@"%02x", bytes[i]];
    }
    return [hex copy];
}

+ (NSData *)dataFromHexString:(NSString *)hexString {
    if (!hexString || hexString.length % 2 != 0) return nil;
    
    NSMutableData *data = [NSMutableData dataWithCapacity:hexString.length / 2];
    for (NSUInteger i = 0; i < hexString.length; i += 2) {
        NSString *hex = [hexString substringWithRange:NSMakeRange(i, 2)];
        unsigned int value;
        [[NSScanner scannerWithString:hex] scanHexInt:&value];
        unsigned char byte = value;
        [data appendBytes:&byte length:1];
    }
    return [data copy];
}

+ (NSString *)calculateFileHash:(NSString *)filePath algorithm:(NSString *)algorithm {
    if (!filePath || ![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        return nil;
    }
    
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    if (!fileHandle) return nil;
    
    CC_MD5_CTX md5Context;
    CC_SHA1_CTX sha1Context;
    CC_SHA256_CTX sha256Context;
    
    if ([algorithm isEqualToString:@"MD5"]) {
        CC_MD5_Init(&md5Context);
    } else if ([algorithm isEqualToString:@"SHA1"]) {
        CC_SHA1_Init(&sha1Context);
    } else if ([algorithm isEqualToString:@"SHA256"]) {
        CC_SHA256_Init(&sha256Context);
    } else {
        [fileHandle closeFile];
        return nil;
    }
    
    NSData *buffer;
    const NSUInteger bufferSize = 1024 * 1024; // 1MB buffer
    
    while ((buffer = [fileHandle readDataOfLength:bufferSize]) && buffer.length > 0) {
        if ([algorithm isEqualToString:@"MD5"]) {
            CC_MD5_Update(&md5Context, buffer.bytes, (CC_LONG)buffer.length);
        } else if ([algorithm isEqualToString:@"SHA1"]) {
            CC_SHA1_Update(&sha1Context, buffer.bytes, (CC_LONG)buffer.length);
        } else if ([algorithm isEqualToString:@"SHA256"]) {
            CC_SHA256_Update(&sha256Context, buffer.bytes, (CC_LONG)buffer.length);
        }
    }
    
    [fileHandle closeFile];
    
    unsigned char digest[CC_SHA256_DIGEST_LENGTH];
    NSUInteger digestLength;
    
    if ([algorithm isEqualToString:@"MD5"]) {
        CC_MD5_Final(digest, &md5Context);
        digestLength = CC_MD5_DIGEST_LENGTH;
    } else if ([algorithm isEqualToString:@"SHA1"]) {
        CC_SHA1_Final(digest, &sha1Context);
        digestLength = CC_SHA1_DIGEST_LENGTH;
    } else if ([algorithm isEqualToString:@"SHA256"]) {
        CC_SHA256_Final(digest, &sha256Context);
        digestLength = CC_SHA256_DIGEST_LENGTH;
    }
    
    NSMutableString *result = [NSMutableString stringWithCapacity:digestLength * 2];
    for (NSUInteger i = 0; i < digestLength; i++) {
        [result appendFormat:@"%02x", digest[i]];
    }
    
    return [result copy];
}

+ (NSString *)aesEncryptToBase64:(NSString *)json key:(NSString *)key iv:(NSString *)iv {
    NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData  = [iv dataUsingEncoding:NSUTF8StringEncoding];

    size_t bufferSize = data.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyData.bytes,
                                          kCCKeySizeAES128,
                                          ivData.bytes,
                                          data.bytes,
                                          data.length,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSData *encryptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        return [encryptedData base64EncodedStringWithOptions:0];
    }
    
    free(buffer);
    return nil;
}

+ (NSString *)sha256ForString:(NSString *)input {
    const char *str = [input UTF8String];
    unsigned char result[CC_SHA256_DIGEST_LENGTH];

    CC_SHA256(str, (CC_LONG)strlen(str), result);

    NSMutableString *hash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [hash appendFormat:@"%02x", result[i]];
    }
    return hash;
}

@end 
